package com.note.gateway.config;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.note.common.vo.ResponseVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.web.WebProperties;
import org.springframework.boot.autoconfigure.web.reactive.error.AbstractErrorWebExceptionHandler;
import org.springframework.boot.web.error.ErrorAttributeOptions;
import org.springframework.boot.web.reactive.error.ErrorAttributes;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.codec.ServerCodecConfigurer;
import org.springframework.web.reactive.function.server.*;
import org.springframework.web.server.ResponseStatusException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.nio.charset.StandardCharsets;
import java.util.Map;

/**
 * 网关全局错误处理配置
 * 处理"No HandlerFound"等Spring WebFlux错误
 */
@Slf4j
@Configuration
public class ErrorWebFluxAutoConfiguration {

    @Bean
    public WebProperties.Resources resources() {
        return new WebProperties.Resources();
    }

    /**
     * 自定义路由处理错误处理器
     */
    @Bean
    @Order(-2)
    public RouteNotFoundWebExceptionHandler routeNotFoundWebExceptionHandler(
            ErrorAttributes errorAttributes,
            WebProperties webProperties,
            ApplicationContext applicationContext,
            ServerCodecConfigurer configurer,
            ObjectMapper objectMapper) {
        RouteNotFoundWebExceptionHandler exceptionHandler = new RouteNotFoundWebExceptionHandler(
                errorAttributes, 
                webProperties.getResources(),
                applicationContext, 
                objectMapper);
        exceptionHandler.setMessageWriters(configurer.getWriters());
        return exceptionHandler;
    }

    /**
     * 路由404处理器
     */
    @Slf4j
    public static class RouteNotFoundWebExceptionHandler extends AbstractErrorWebExceptionHandler {
        
        private final ObjectMapper objectMapper;

        public RouteNotFoundWebExceptionHandler(
                ErrorAttributes errorAttributes,
                WebProperties.Resources resources,
                ApplicationContext applicationContext,
                ObjectMapper objectMapper) {
            super(errorAttributes, resources, applicationContext);
            this.objectMapper = objectMapper;
        }

        @Override
        protected RouterFunction<ServerResponse> getRoutingFunction(ErrorAttributes errorAttributes) {
            return RouterFunctions.route(RequestPredicates.all(), this::renderErrorResponse);
        }

        private Mono<ServerResponse> renderErrorResponse(ServerRequest request) {
            Map<String, Object> errorAttributes = getErrorAttributes(request, ErrorAttributeOptions.defaults());
            Throwable error = getError(request);
            log.warn("请求处理错误: path={}, error={}", request.path(), error.getMessage());
            
            int status = getHttpStatus(errorAttributes);
            ResponseVo<?> responseVo;
            
            // 根据状态码返回不同的错误消息
            if (status == HttpStatus.NOT_FOUND.value()) {
                responseVo = ResponseVo.error(status, "请求的资源不存在");
            } else if (status == HttpStatus.METHOD_NOT_ALLOWED.value()) {
                responseVo = ResponseVo.error(status, "请求方法不被允许");
            } else if (status == HttpStatus.BAD_REQUEST.value()) {
                responseVo = ResponseVo.error(status, "错误的请求");
            } else if (status >= 500) {
                responseVo = ResponseVo.error(status, "服务器内部错误");
            } else {
                responseVo = ResponseVo.error(status, "请求处理失败");
            }

            // 处理特定异常
            if (error instanceof ResponseStatusException) {
                ResponseStatusException ex = (ResponseStatusException) error;
                if (ex.getReason() != null) {
                    responseVo = ResponseVo.error(status, ex.getReason());
                }
            }
            
            // 返回JSON格式的错误响应
            return ServerResponse
                    .status(status)
                    .contentType(MediaType.APPLICATION_JSON)
                    .bodyValue(responseVo);
        }

        /**
         * 从错误属性中获取HTTP状态码
         */
        private int getHttpStatus(Map<String, Object> errorAttributes) {
            Object status = errorAttributes.get("status");
            if (status instanceof Integer) {
                return (Integer) status;
            }
            return HttpStatus.INTERNAL_SERVER_ERROR.value();
        }
    }
} 